package br.usp.ime.dojo.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;

public class RoomDisplay extends Composite {

	private VerticalPanel vPanel_left;
	private VerticalPanel vPanel_right;
	private HorizontalPanel hPanel;
	private HorizontalPanel descriptionAndLanguageHPNL;
	private VerticalPanel languageAndStartSessionVPNL;
	private VerticalPanel descriptionLabelAndAreaVPNL;
	private Chat chat;
	private Label descriptionLabel;
	private Button startSessionBTN;
	private Label startSessionErrorLBL;
	private TextArea descriptionArea;
	private List<CheckBox> languagesSelection;
	private TabPanel codeTabPanel;
	private TabPanel testTabPanel;
	private HorizontalSplitPanel codeAndTestSplitPanel;
	

	private Button exitRoomBTN;
	private boolean isStarted;

	private DojoRoomServiceAsync dojoRoomServiceAsync;
	private PilotListWidget pilotListWidget;
	private ChatServiceAsync chatServiceAsync;

	private UserListWidget userListWidget;
	private DojoRoomDTO dojoRoomDTO;
	private UserDTO userDTO;
	private final int REFRESH_TIME = 1000;

	private ExitARoomListener exitARoomListener;
	protected Button compileBTN;
	private CodeArea codeArea;

	private JRubyInterpreterServiceAsync runJruby;
	private boolean isDojoRoomUpdated = false;

	public RoomDisplay(DojoRoomDTO room, UserDTO loggedUser) {

		dojoRoomDTO = room;
		userDTO = loggedUser;
		isStarted = false;

		vPanel_left = new VerticalPanel();
		vPanel_right = new VerticalPanel();
		hPanel = new HorizontalPanel();

		descriptionLabelAndAreaVPNL = new VerticalPanel();
		descriptionAndLanguageHPNL = new HorizontalPanel();
		languageAndStartSessionVPNL = new VerticalPanel();

		startSessionErrorLBL = new Label();

		compileBTN = new Button("Run");
		compileBTN.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				runIt();
			}

		});
		// TODO click handler for compile/run tests button

		dojoRoomServiceAsync = GWT.create(DojoRoomService.class);
		chatServiceAsync = GWT.create(ChatService.class);

		createDescriptionArea();
		createLanguagesList();

		createExitRoomButton();

		descriptionAndLanguageHPNL.setWidth("100%");
		hPanel.setWidth("90%");
		vPanel_left.setWidth("90%");
		vPanel_right.setWidth("10%");

		dojoRoomServiceAsync.join(dojoRoomDTO, userDTO, onJoinCallback());

		createUpdateRoomTimer();

		// TODO - Expand description horizontal size
		descriptionLabelAndAreaVPNL.setWidth("100%");
		languageAndStartSessionVPNL.setWidth("100%");
		//languageAndStartSessionVPNL.setBorderWidth(1);

		descriptionAndLanguageHPNL.add(descriptionLabelAndAreaVPNL);
		descriptionAndLanguageHPNL.add(languageAndStartSessionVPNL);
		descriptionAndLanguageHPNL.setCellWidth(descriptionLabelAndAreaVPNL, "80%");
		descriptionAndLanguageHPNL.setCellWidth(languageAndStartSessionVPNL, "20%");

		vPanel_left.add(descriptionAndLanguageHPNL);

		hPanel.add(exitRoomBTN);

		hPanel.add(vPanel_left);
		hPanel.add(vPanel_right);

		initWidget(hPanel);
	}

	protected void runIt() {
		if (runJruby == null)
			runJruby = GWT.create(JRubyInterpreterService.class);
		runJruby.interpret(codeArea.getCodeAreaText(), codeArea.getTestAreaText(), new AsyncCallback<String>() {
			// Obs: We still havent put the test code tabpanel.
			public void onFailure(Throwable caught) {
				updateResultAreaInServer("Error: " + caught.getMessage());	
				//caught.printStackTrace();
			}
			public void onSuccess(String result) {
				//codeArea.setResultAreaText(result);
				updateResultAreaInServer(result);															
			}
		});
	}

	public void updateResultAreaInServer(String result) {
	AsyncCallback<Void> callback = new AsyncCallback<Void>() {
		public void onFailure(Throwable caught) {
		}
		public void onSuccess(Void result) {
		}
	};
		dojoRoomServiceAsync.updateResultCodeInServer(result , callback);
	}

	
	private void createStartSessionButton() {
		startSessionBTN = new Button("Start Session");
		startSessionBTN.addClickHandler(startSessionClickHandler());
		languageAndStartSessionVPNL.add(startSessionBTN);
		startSessionErrorLBL.setStyleName("dojoError");
		languageAndStartSessionVPNL.add(startSessionErrorLBL);
	}

	private ClickHandler startSessionClickHandler() {
		return new ClickHandler() {
			public void onClick(ClickEvent event) {
				startSession();
			}
		};
	}

	private void startSession() {
		AsyncCallback<Void> callback = new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
				startSessionErrorLBL.setText(caught.getMessage());

			}
			public void onSuccess(Void result) {
				isStarted = true;	
			}

		};
		dojoRoomServiceAsync.startSession(dojoRoomDTO.getName(), callback);
	}

	private void createDescriptionArea() {
		descriptionLabel = new Label("Description: ");
		descriptionArea = new TextArea();
		descriptionArea.setWidth("100%"); 
		getRoomDescription();
		descriptionArea.setEnabled(false);

		descriptionLabelAndAreaVPNL.add(descriptionLabel);
		descriptionLabelAndAreaVPNL.add(descriptionArea);
	}
	private void updateDojoRoomToStartedRoom() {
		if (isDojoRoomUpdated) {
			return;
		}
		isDojoRoomUpdated = true;
		
		vPanel_left.remove(descriptionAndLanguageHPNL);
		//languageAndStartSessionVPNL.remove(startSessionErrorLBL);
		//vPanel_left.remove(descriptionLabel);
		vPanel_left.remove(chat);
		//Building the header panel (description+compile button)
		HorizontalPanel headerPanel = new HorizontalPanel();
		headerPanel.setWidth("100%");
		VerticalPanel leftHeaderPanel = new VerticalPanel();
		VerticalPanel rightHeaderPanel = new VerticalPanel();
		rightHeaderPanel.setWidth("100%");
		rightHeaderPanel.setHeight("100%");
		rightHeaderPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_BOTTOM);
		rightHeaderPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		rightHeaderPanel.add(compileBTN);
		headerPanel.add(leftHeaderPanel);
		headerPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_BOTTOM);
		headerPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		headerPanel.add(rightHeaderPanel);

		vPanel_left.setVerticalAlignment(HasVerticalAlignment.ALIGN_BOTTOM);
		vPanel_left.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		vPanel_left.add(headerPanel);
		vPanel_left.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
		vPanel_left.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);

		codeAndTestSplitPanel = new HorizontalSplitPanel();
		vPanel_left.add(codeAndTestSplitPanel);
		vPanel_left.setCellHeight(codeAndTestSplitPanel,"220px");
		//tabpanel goes here
		codeTabPanel = new TabPanel();
		codeArea = new CodeArea();
		codeTabPanel.add(codeArea.getCodeArea(),"Code");
		codeTabPanel.add(codeArea.getResultArea(),"Results");
		codeTabPanel.selectTab(0);
		codeAndTestSplitPanel.add(codeTabPanel);
		codeTabPanel.setWidth("100%");
		codeTabPanel.setHeight("95%");
		
		testTabPanel = new TabPanel();
		testTabPanel.add(codeArea.getTestArea(),"Test");
		testTabPanel.selectTab(0);
		codeAndTestSplitPanel.add(testTabPanel);
		testTabPanel.setWidth("100%");
		testTabPanel.setHeight("95%");
		
	
		
		vPanel_left.add(chat);
	}
	private void createLanguagesList() {
		AsyncCallback<List<String>> callback = new AsyncCallback<List<String>>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(List<String> result) {
				languagesSelection = new ArrayList<CheckBox>();
				for (String s : result) {
					CheckBox cb = new CheckBox(s);
					languagesSelection.add(cb);
					cb.setValue(true);
					if (!userDTO.getName().equals(
							dojoRoomDTO.getCreator().getName()))
						cb.setEnabled(false);
					else {
						cb.addClickHandler(checkBoxListener());
					}
					languageAndStartSessionVPNL.add(cb);
				}
				if(userDTO.getName().equals(dojoRoomDTO.getCreator().getName())){
					createStartSessionButton();
				}
				updateLanguagesSelection();
			}
		};
		dojoRoomServiceAsync.getInitialLanguages(dojoRoomDTO.getName(),
				callback);
	}

	private ClickHandler checkBoxListener() {
		return new ClickHandler() {
			public void onClick(ClickEvent sender) {
				AsyncCallback<List<String>> callback = new AsyncCallback<List<String>>() {
					public void onFailure(Throwable caught) {
					}

					public void onSuccess(List<String> result) {
					}
				};
				dojoRoomServiceAsync.setSelectedLanguages(
						dojoRoomDTO.getName(), ((CheckBox) sender.getSource())
						.getText(), callback);
			}
		};
	}	

	private void createUpdateRoomTimer() {
		Timer time = new Timer() {
			public void run() {
				if (isStarted == false) {
					if (!userDTO.getName().equals(
							dojoRoomDTO.getCreator().getName())) {
						updateLanguagesSelection();
						getRoomDescription();
					} else {
						setRoomDescription();							
					}
					verifyIfStartedSession();
				}
				else {
					updateDojoRoomToStartedRoom();
					if(userDTO.getName().equals(pilotListWidget.getPilot())) {
						codeArea.setCodeAreaReadOnly(false);
						codeArea.setTestAreaReadOnly(false);
						codeArea.scheduleRepeating(REFRESH_TIME);
						//TODO Precisa definir comportamento do copiloto
						//if(userDTO.getName().equals(pilotListWidget.getCopilot())) {
						//	codeArea.setReadOnly(false);
						//}
						
						compileBTN.setEnabled(true);
					}
					else{
						codeArea.setCodeAreaReadOnly(true);
						codeArea.setTestAreaReadOnly(true);
						codeArea.scheduleRepeating(REFRESH_TIME);
						
						compileBTN.setEnabled(false);
					}
				}
			}			
		};

		time.scheduleRepeating(REFRESH_TIME);
	}
	private void verifyIfStartedSession() {
		if(dojoRoomServiceAsync == null)
			dojoRoomServiceAsync = GWT.create(DojoRoomService.class);
		dojoRoomServiceAsync.verifyIfIsStarted(dojoRoomDTO.getName(), new AsyncCallback<Boolean>(){


			public void onFailure(Throwable caught) {

			}

			public void onSuccess(Boolean result) {
				isStarted = result;
			}

		});

	}
	protected void setRoomDescription() {
		AsyncCallback<Void> callback = new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(Void result) {
			}
		};
		dojoRoomServiceAsync.setRoomDescription(descriptionArea.getText(),
				dojoRoomDTO.getName(), callback);
	}

	private void getRoomDescription() {
		AsyncCallback<String> callback = new AsyncCallback<String>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(String description) {
				descriptionArea.setText(description);
				if (dojoRoomDTO.getCreator().getName()
						.equals(userDTO.getName())) {
					descriptionArea.setEnabled(true);
				}
			}
		};
		dojoRoomServiceAsync
		.getRoomDescription(dojoRoomDTO.getName(), callback);
	}

	private AsyncCallback<Void> onJoinCallback() {
		return new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
				// it may throw user already in the room exception. TODO catch
				// it...
				/*
				 * descriptionLabel = new Label();
				 * descriptionLabel.setText(caught.getMessage());
				 * vPanel_left.add(descriptionLabel);
				 */
			}

			public void onSuccess(Void nul) {
				setRoomDisplayInterface();
			}
		};
	}

	private void createExitRoomButton() {
		exitRoomBTN = new Button("Exit Room");
		exitRoomBTN.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				exitUserFromRoom();
				exitARoomListener.onExitDojoRoom();
			}

		});
	}

	private void updateLanguagesSelection() {
		AsyncCallback<List<String>> callback = new AsyncCallback<List<String>>() {

			public void onFailure(Throwable caught) {

			}

			public void onSuccess(List<String> result) {
				if (languagesSelection != null) {
					for (CheckBox cb : languagesSelection) {
						if (result.contains(cb.getText())) {
							cb.setValue(true);
						} else
							cb.setValue(false);

					}
				}
			}
		};
		dojoRoomServiceAsync.getSelectedLanguages(dojoRoomDTO.getName(),
				callback);

	}

	private void exitDojoRoom(String userName, String dojoRoomName) {
		AsyncCallback<Void> callback = new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(Void result) {
			}
		};
		dojoRoomServiceAsync.exitDojoRoom(userName, dojoRoomName, callback);
	}

	private void exitChat(String userName, String dojoRoomName) {
		AsyncCallback<Void> callback = new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(Void result) {
				chat.cancel();
			}
		};
		chatServiceAsync.unregisterUser(userName, dojoRoomName, callback);
	}

	public void setExitADojoRoomListener(ExitARoomListener listener) {
		exitARoomListener = listener;
	}

	private void setRoomDisplayInterface() {
		chat = new Chat(userDTO.getName(), dojoRoomDTO.getName());
		vPanel_left.add(chat);

		pilotListWidget = new PilotListWidget(userDTO, dojoRoomDTO);
		vPanel_right.add(pilotListWidget);

		userListWidget = new UserListWidget(dojoRoomDTO.getName());
		vPanel_right.add(userListWidget);
	}

	public void exitUserFromRoom() {
		exitDojoRoom(userDTO.getName(), dojoRoomDTO.getName());
		exitChat(userDTO.getName(), dojoRoomDTO.getName());
	}
}
